package com.xinruke.hostels.dailymanage.service;

import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.xinruke.hostels.common.cache.ManageUserCache;
import com.xinruke.hostels.common.constants.RedisConstants;
import com.xinruke.hostels.common.constants.SysDicConstant;
import com.xinruke.hostels.common.exception.BizException;
import com.xinruke.hostels.common.mybatis.MyExample;
import com.xinruke.hostels.common.po.*;
import com.xinruke.hostels.common.po.constants.*;
import com.xinruke.hostels.common.service.OperateLogService;
import com.xinruke.hostels.common.util.CustomSecurity;
import com.xinruke.hostels.common.vo.ResultVO;
import com.xinruke.hostels.common.vo.query.EConditionOperator;
import com.xinruke.hostels.common.vo.query.QueryConditions;
import com.xinruke.hostels.common.vo.query.RowsDataVO;
import com.xinruke.hostels.dailymanage.interfaces.dto.inhotel.*;
import com.xinruke.hostels.dailymanage.mapper.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @ClassName OrderSettleService
 * @CreateDate 2019/7/12
 * @Author FengXinQiang
 * @Version V1.0.0.0
 * @Decription 订单结算Service
 */
@Service
@Slf4j
public class OrderSettleService {
    @Autowired
    YwYudingDingdanMapper yudingDingdanMapper;

    @Autowired
    YwRuzhuDingdanMapper ruzhuDingdanMapper;

    @Autowired
    YwRuzhuDingdanZixiangMapper ruzhuDingdanZixiangMapper;

    @Autowired
    YwDingdanshouzhijiluMapper dingdanshouzhijiluMapper;

    @Autowired
    YwFangtairiqijiluMapper fangtairiqijiluMapper;

    @Autowired
    YwFangjianMapper fangjianMapper;

    @Autowired
    OperateLogService operateLogService;

    @Autowired
    ManageUserCache manageUserCache;

    @Resource(name = "commonRedisTemplate")
    RedisTemplate commonRedisTemplate;

    /**
     * 获取资金流水集合
     *
     * @param orderFundsFlowQueryDTO
     * @return
     */
    public RowsDataVO<OrderFundsFlowQueryResultDTO> getFundsFlowList(OrderFundsFlowQueryDTO orderFundsFlowQueryDTO) {
        RowsDataVO<OrderFundsFlowQueryResultDTO> rowsDataVO = new RowsDataVO<>();

        QueryConditions queryConditions = orderFundsFlowQueryDTO.getQueryConditions();
        queryConditions.addCondition("jiudianId", EConditionOperator.EQULS, manageUserCache.getJiudianId());
        queryConditions.addCondition("shanchubiaoshi", EConditionOperator.EQULS, SysDicConstant.DELFLAG_0);
        queryConditions.addCondition("dingdanId", EConditionOperator.EQULS, orderFundsFlowQueryDTO.getDingdanId());
        queryConditions.addCondition("dingdanhao", EConditionOperator.EQULS, orderFundsFlowQueryDTO.getDingdanhao());

        MyExample myExample = new MyExample(YwDingdanshouzhijilu.class, queryConditions);
        Page<YwDingdanshouzhijilu> page = PageHelper.startPage(orderFundsFlowQueryDTO.getPageNo(), orderFundsFlowQueryDTO.getPageSize());
        List<YwDingdanshouzhijilu> resultList = dingdanshouzhijiluMapper.selectByExample(myExample);

        List<OrderFundsFlowQueryResultDTO> dataList = resultList.stream().map(m -> {
            OrderFundsFlowQueryResultDTO orderFundsFlowQueryResultDTO = new OrderFundsFlowQueryResultDTO();
            BeanUtils.copyProperties(m, orderFundsFlowQueryResultDTO);
            return orderFundsFlowQueryResultDTO;
        }).collect(Collectors.toList());

        rowsDataVO.setPageNo(page.getPageNum());
        rowsDataVO.setTotalRecords(page.getTotal());
        rowsDataVO.setTotalPages(page.getPages());
        rowsDataVO.setRows(dataList);

        return rowsDataVO;
    }

    /**
     * 入账
     *
     * @param orderInMoneyDTO
     * @return
     */
    public ResultVO<OrderInMoneyResultDTO> orderInMoney(OrderInMoneyDTO orderInMoneyDTO) {
        ResultVO<OrderInMoneyResultDTO> resultVO = ResultVO.fail();

        int dingdanId = orderInMoneyDTO.getDingdanId();
        YwRuzhuDingdan ruzhuDingdan = ruzhuDingdanMapper.selectByPrimaryKey(dingdanId);
        if (ruzhuDingdan == null) {
            resultVO.setMessage("该订单不存在");
            return resultVO;
        }

        YwDingdanshouzhijilu dingdanshouzhijilu = new YwDingdanshouzhijilu();
        BeanUtils.copyProperties(orderInMoneyDTO, dingdanshouzhijilu);

        dingdanshouzhijilu.setJiudianId(manageUserCache.getJiudianId());
        dingdanshouzhijilu.setChuangjianshijian(new Date());
        dingdanshouzhijilu.setDingdanhao(ruzhuDingdan.getDingdanhao());
        dingdanshouzhijilu.setDingdanId(ruzhuDingdan.getId());
        dingdanshouzhijilu.setGengxinshijian(new Date());
        dingdanshouzhijilu.setShanchubiaoshi(SysDicConstant.DELFLAG_0);
        dingdanshouzhijilu.setZhengjianId(ruzhuDingdan.getYudingrenshenfenId());
        dingdanshouzhijilu.setZhengjianleixing(ruzhuDingdan.getZhengjianleixing());
        dingdanshouzhijilu.setZhengjianhao(ruzhuDingdan.getZhengjianhao());
        dingdanshouzhijilu.setZhuangtai(YwDingdanshouzhijiluConstants.ZHUANGTAI_YOUXIAO);

        int shouzhiRet = dingdanshouzhijiluMapper.insertSelective(dingdanshouzhijilu);
        if (shouzhiRet <= 0) {
            resultVO.setMessage("收支记录写入失败");
            return resultVO;
        }

        //写入操作日志
        YewuyonghuCaozuoRizhi yewuyonghuCaozuoRizhi = new YewuyonghuCaozuoRizhi("入账", "入账", "订单号[" + ruzhuDingdan.getDingdanhao() + "]");
        operateLogService.writeOperateLog(yewuyonghuCaozuoRizhi);

        resultVO = ResultVO.success();

        return resultVO;
    }


    /**
     * 结账退房
     * <p>
     * 1.Redis加锁
     * 2.修改入住订单为已离店
     * 3.修改预订订单为已离店
     * 4.写入订单支出记录
     * 5.解锁房间为空脏
     * 6.写入操作日志
     *
     * @param orderSettleDTO
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public ResultVO<OrderSettleResultDTO> settleRoom(OrderSettleDTO orderSettleDTO) {
        String traceId = CustomSecurity.getTraceID();
        log.info("traceId[" + traceId + "]" + JSONObject.toJSONString(orderSettleDTO));

        ResultVO<OrderSettleResultDTO> resultVO = ResultVO.fail();

        int jiudianId = manageUserCache.getJiudianId();
        String redisLockKey = RedisConstants.HOTEL_ROOM_LOCK_KEY_PREFIX + jiudianId;
        try {
            //使用redis，根据酒店id对房间操作加锁
            boolean lockRet = commonRedisTemplate.opsForValue().setIfAbsent(redisLockKey, jiudianId);
            if (!lockRet) {
                log.error("traceId[" + traceId + "]房间冲突，请重试");
                resultVO.setMessage("房间冲突，请重试");
                return resultVO;
            }

            int ruzhuId = orderSettleDTO.getRuzhuId();
            QueryConditions dingdanQueryCondition = new QueryConditions();
            dingdanQueryCondition.addCondition("jiudianId", EConditionOperator.EQULS, jiudianId);
            dingdanQueryCondition.addCondition("id", EConditionOperator.EQULS, ruzhuId);
            dingdanQueryCondition.addCondition("shanchubiaoshi", EConditionOperator.EQULS, SysDicConstant.DELFLAG_0);
            MyExample dingdanMyExample = new MyExample(YwYudingDingdan.class, dingdanQueryCondition);
            List<YwRuzhuDingdan> ruzhuDingdanList = ruzhuDingdanMapper.selectByExample(dingdanMyExample);
            if (CollectionUtils.isEmpty(ruzhuDingdanList)) {
                log.error("traceId[" + traceId + "]入住订单不存在");
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                resultVO.setMessage("入住订单不存在");
                return resultVO;
            }

            YwRuzhuDingdan ruzhuDingdan = ruzhuDingdanList.get(0);
            byte zhuangtai = ruzhuDingdan.getZhuangtai();
            if (zhuangtai != YwRuzhuDingdanConstants.ZHUANGTAI_YIRUZHU) {
                log.error("traceId[" + traceId + "]该订单不能结账退房");
                resultVO.setMessage("该订单不能结账退房");
                return resultVO;
            }

            //修改入住订单为已离店
            ruzhuDingdan.setZhuangtai(YwRuzhuDingdanConstants.ZHUANGTAI_YILIDIAN);
            ruzhuDingdan.setJiezhangzhuangtai(YwRuzhuDingdanConstants.JIEZHANGZHUANGTAI_YIJIE);
            /*//修改入住订单的实收金额
            ruzhuDingdan.setShishoujine(orderSettleDTO.getJine());*/
            int rezhuRet = ruzhuDingdanMapper.updateByPrimaryKeySelective(ruzhuDingdan);
            if (rezhuRet <= 0) {
                log.error("traceId[" + traceId + "]入住订单修改失败");
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                resultVO.setMessage("入住订单修改失败");
                return resultVO;
            }

            //修改预订订单为已离店
            Integer yudingId = ruzhuDingdan.getYudingdingdanId();
            if (yudingId != null && yudingId != 0) {
                YwYudingDingdan yudingDingdan = yudingDingdanMapper.selectByPrimaryKey(yudingId);
                if (yudingDingdan == null) {
                    log.error("traceId[" + traceId + "]预订单不存在");
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    resultVO.setMessage("预订单不存在");
                    return resultVO;
                }
                yudingDingdan.setZhuangtai(YwYudingDingdanConstants.ZHUANGTAI_YIWANCHENG);
                int yudingdanRet = yudingDingdanMapper.updateByPrimaryKeySelective(yudingDingdan);
                if (yudingdanRet <= 0) {
                    log.error("traceId[" + traceId + "]预订单修改失败");
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    resultVO.setMessage("预订单修改失败");
                    return resultVO;
                }
            }

            //写入订单收支记录
            YwDingdanshouzhijilu dingdanshouzhijilu = new YwDingdanshouzhijilu();
            dingdanshouzhijilu.setLeibie(YwDingdanshouzhijiluConstants.LEIBIE_DINGDANSHISHOUJINE);
            dingdanshouzhijilu.setFukuanfangshi(orderSettleDTO.getFukuanfangshi());
            dingdanshouzhijilu.setJine(orderSettleDTO.getJine());
            dingdanshouzhijilu.setBeizhu(orderSettleDTO.getBeizhu() + orderSettleDTO.getGuazhangyuanyin());
            dingdanshouzhijilu.setJiudianId(jiudianId);
            dingdanshouzhijilu.setChuangjianshijian(new Date());
            dingdanshouzhijilu.setDingdanhao(ruzhuDingdan.getDingdanhao());
            dingdanshouzhijilu.setDingdanId(ruzhuDingdan.getId());
            dingdanshouzhijilu.setGengxinshijian(new Date());
            dingdanshouzhijilu.setShanchubiaoshi(SysDicConstant.DELFLAG_0);
            dingdanshouzhijilu.setZhengjianId(ruzhuDingdan.getYudingrenshenfenId());
            dingdanshouzhijilu.setZhengjianleixing(ruzhuDingdan.getZhengjianleixing());
            dingdanshouzhijilu.setZhengjianhao(ruzhuDingdan.getZhengjianhao());
            dingdanshouzhijilu.setZhuangtai(YwDingdanshouzhijiluConstants.ZHUANGTAI_YOUXIAO);

            int shouzhiRet = dingdanshouzhijiluMapper.insertSelective(dingdanshouzhijilu);
            if (shouzhiRet <= 0) {
                resultVO.setMessage("收支记录写入失败");
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return resultVO;
            }

            //解锁房间
            QueryConditions fangjianQueryCondition = new QueryConditions();
            fangjianQueryCondition.addCondition("dingdanId", EConditionOperator.EQULS, ruzhuId);
            fangjianQueryCondition.addCondition("shanchubiaoshi", EConditionOperator.EQULS, SysDicConstant.DELFLAG_0);
            MyExample fangjianMyExample = new MyExample(YwRuzhuDingdanZixiang.class, fangjianQueryCondition);
            List<YwRuzhuDingdanZixiang> ruzhuDingdanZixiangList = ruzhuDingdanZixiangMapper.selectByExample(fangjianMyExample);
            for (YwRuzhuDingdanZixiang ruzhuDingdanZixiang : ruzhuDingdanZixiangList) {
                int fangjianId = ruzhuDingdanZixiang.getFangjianId();

                QueryConditions fangtairiqijiluQueryCondition = new QueryConditions();
                fangtairiqijiluQueryCondition.addCondition("jiudianId", EConditionOperator.EQULS, ruzhuDingdanZixiang.getJiudianId());
                fangtairiqijiluQueryCondition.addCondition("fangjianId", EConditionOperator.EQULS, fangjianId);
                fangtairiqijiluQueryCondition.addCondition("kaishishijian", EConditionOperator.EQULS, ruzhuDingdanZixiang.getRuzhushijian());
                fangtairiqijiluQueryCondition.addCondition("jieshushijian", EConditionOperator.EQULS, ruzhuDingdanZixiang.getLikaishijian());
                fangtairiqijiluQueryCondition.addCondition("shanchubiaoshi", EConditionOperator.EQULS, SysDicConstant.DELFLAG_0);
                fangtairiqijiluQueryCondition.addCondition("fangjianleibie", EConditionOperator.EQULS, YwFangtairiqijiluConstants.FANGJIANLEIBIE_FANGJIAN);
                MyExample fangtairiqijiluMyExample = new MyExample(YwFangtairiqijilu.class, fangtairiqijiluQueryCondition);
                YwFangtairiqijilu fangtairiqijilu = new YwFangtairiqijilu();
                fangtairiqijilu.setShanchubiaoshi(SysDicConstant.DELFLAG_1);

                int fangtaiRet = fangtairiqijiluMapper.updateByExampleSelective(fangtairiqijilu, fangtairiqijiluMyExample);
                if (fangtaiRet <= 0) {
                    log.error("traceId[" + traceId + "]修改房态失败");
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    resultVO.setMessage("修改房态失败");
                    return resultVO;
                }

                //根据房间id，获取房间信息
                YwFangjian fangjian = fangjianMapper.selectByPrimaryKey(fangjianId);

                //修改房间表状态
                fangjian.setZhuangtai(YwFangjianConstants.ZHUANGTAI_KONGZANG);
                int fangjianRet = fangjianMapper.updateByPrimaryKeySelective(fangjian);
                if (fangjianRet <= 0) {
                    log.error("traceId[" + traceId + "]房间表修改失败");
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    resultVO.setMessage("房间表修改失败");
                    return resultVO;
                }
            }

            //写入操作日志
            YewuyonghuCaozuoRizhi yewuyonghuCaozuoRizhi = new YewuyonghuCaozuoRizhi("结账退房", "结账退房", "订单号[" + ruzhuDingdan.getDingdanhao() + "]");
            operateLogService.writeOperateLog(yewuyonghuCaozuoRizhi);

            resultVO = ResultVO.success();
            resultVO.setMessage("结账退房成功");
        } catch (Exception e) {
            log.error("traceId[" + traceId + "]结账退房失败，系统异常", e);
            throw new BizException("结账退房失败，系统异常");
        } finally {
            commonRedisTemplate.delete(redisLockKey);
        }

        return resultVO;
    }
}
